package com.rockcent.wechat.controller;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.rockcent.common.common.JsonResult;
import com.rockcent.common.common.PageResult;
import com.rockcent.common.common.RestDoing;
import com.rockcent.common.controller.BaseController;
import com.rockcent.common.domain.enumclass.Whether;
import com.rockcent.common.utils.RBeanUtils;
import com.rockcent.common.utils.RDateFormatUtils;
import com.rockcent.common.utils.RDateUtils;
import com.rockcent.helper.SysMessageHelper;
import com.rockcent.mall.lib.constants.SysMessageConstants;
import com.rockcent.mall.lib.domain.*;
import com.rockcent.mall.lib.domain.enumclass.*;
import com.rockcent.mall.lib.dto.*;
import com.rockcent.mall.lib.helper.OrderHelper;
import com.rockcent.mall.lib.helper.QRCodeHelper;
import com.rockcent.mall.lib.repository.*;
import com.rockcent.wechat.Prop;
import com.rockcent.wechat.Routes;
import com.rockcent.wechat.helper.CustomerHelper;
import org.apache.commons.lang3.EnumUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.text.MessageFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * Created by HK on 16/10/17.
 */
@RestController
@RequestMapping(value = Routes.API_PREFIX)
public class CustomerCouponController extends BaseController {

    private static final Logger log = LoggerFactory.getLogger(CustomerCouponController.class);
    @Autowired
    private MallRepository mallRepository;
    @Autowired
    private MerchantCouponRepository merchantCouponRepository;
    @Autowired
    private MerchantProductRepository merchantProductRepository;
    @Autowired
    private MerchantStoreRepository merchantStoreRepository;
    @Autowired
    private MerchantCouponProductsRepository merchantCouponProductsRepository;
    @Autowired
    private CustomerCouponWalletRepository customerCouponWalletRepository;
    @Autowired
    private CouponMerchantStoreRepository couponMerchantStoreRepository;
    @Autowired
    private MerchantStoreCustomerRepository merchantStoreCustomerRepository;
    @Autowired
    private Prop prop;
    @Autowired
    private ObjectMapper objectMapper;
    @Autowired
    private CustomerHelper customerHelper;
    @Autowired
    private QRCodeHelper qrCodeHelper;

    @Autowired
    private CouponRepository couponRepository;

    /**
     * @api {put} /api/v2/customer/coupon/create/verify/code 创建核销码
     * @apiGroup CUSTOMER_COUPON
     *
     * @apiHeader {String} domain <code>必须参数</code>对应平台C端域名
     * @apiHeader {String} userToken <code>必须参数</code>用户Token
     *
     * @apiParam {String} id 卡卷ID;
     *
     * @apiSuccess {String} verifyCode 核销码
     * @apiSuccess {String} qrCodeUrl 二维码图片url 页面显示格式为:
     *
     * @apiSuccessExample {json} Success-Response:
     *  {
     *       "code": 1,
     *       "desc": "成功"
     *       "data": {
     *          "verifyCode": "784317",
     *          "qrcCodeUrl": "http://b1.dev.rockcent.com/verifyCoupon.php?CouponVerifyCode=1&MerchantId=2&VerifyCode=784317"
     *       }
     *   }
     **/
    @Transactional
    @RequestMapping(value = Routes.CUSTOMER_COUPON_CREATE_VERIFY_CODE, method = RequestMethod.PUT)
    public JsonResult couponCreateVerifyCode(HttpServletRequest request, @RequestBody MerchantCouponDto dto) {
        CustomerDto customerDto = customerHelper.getSession(request);
        RestDoing doing = jr -> {
            if (dto.getId() == null) {
                jr.remind(MerchantCoupon.CHECK_ID_IS_NOT_NULL,log);;
                return;
            }
            CustomerCouponWallet couponWallet = customerCouponWalletRepository.findByCustomerIdAndCouponIdAndStatus(customerDto.getId(), dto.getId(), CustomerCouponWalletStatus.TO_USE);
            if (couponWallet == null) {
                jr.remind(CustomerCouponWallet.REMIND_RECORD_IS_NOT_EXIST,log);;
                return;
            }
            MerchantCoupon merchantCoupon = merchantCouponRepository.findOne(couponWallet.getCouponId());
            if (merchantCoupon == null) {
                jr.remind("卡券(" + merchantCoupon.getName() + ")不存在!",log);
                return;
            }
            if (CouponUseScope.ALL_STORE != merchantCoupon.getUseScope() && CouponUseScope.PART_STORE != merchantCoupon.getUseScope()) {
                jr.remind("卡券(" + merchantCoupon.getName() + ")不适用于线下门店核销!",log);
                return;
            }
            Integer verifyCode = customerHelper.verifyCode(VerifyType.COUPON);
            String verifyKey = customerHelper.customerCouponCodeMd5(merchantCoupon.getMerchantId(), customerDto.getId(), merchantCoupon.getId(), verifyCode);
            Mall mall = mallRepository.findOne(customerDto.getMallId());
            String host = mall.getCustomerClientDomain();
            if (StringUtils.isBlank(host)) {
                host = mall.getMobileHostName();
            }
            StringBuilder url = new StringBuilder();
            url.append("http://").append(host).append("/?verifyKey=").append(verifyKey).append("&merchantId=").append(merchantCoupon.getMerchantId());
            String qrcCodeUrl = qrCodeHelper.createBase64QRCode(url.toString());
            couponWallet.setVerifyCode(String.valueOf(verifyCode));
            couponWallet.setVerifyKey(verifyKey);
            couponWallet = customerCouponWalletRepository.save(couponWallet);
            couponWallet.setQrcCodeUrl(qrcCodeUrl);
            jr.data = couponWallet;
        };
        return doing.go(request, log);
    }

    /**
     * @api {get} /api/v2/customer/coupon/page 我的卡卷
     * @apiGroup CUSTOMER_COUPON
     *
     * @apiHeader {String} domain <code>必须参数</code>对应平台C端域名
     * @apiHeader {String} userToken <code>必须参数</code>用户Token
     *
     * @apiParam {String} couponStatus <code>必须参数</code> 卡券状态 : TO_USE("待使用"),USED("已使用"), EXPIRED("已过期");
     *
     * @apiSuccess {Long} id 卡券ID
     * @apiSuccess {Long} customerCouponId 客户卡卷ID
     * @apiSuccess {String} logoUrl 卡卷图片
     * @apiSuccess {String=VOUCHERS("抵用券"), DISCOUNT("折扣券")} type 卡片类型
     * @apiSuccess {BigDecimal} faceValue 面值
     * @apiSuccess {BigDecimal} discount 折扣
     * @apiSuccess {BigDecimal} limitAmount 最低消费金额
     * @apiSuccess {Date} dateEnabled 有效开始时间
     * @apiSuccess {Date} dateDisabled 有效结束时间
     * @apiSuccess {String=ALL_STORE("所有门店"), ALL_PRODUCT("所有产品"), PART_STORE("指定门店"), PART_PRODUCT("指定产品")} useScope 适用范围
     * @apiSuccessExample {json} Success-Response:
     *  {
     *      "code": 1,
     *      "desc": "成功",
     *      "data" :{
     *          "data": [{
     *              {
     *              "id": 5,
     *              "customerCouponId": 32,
     *              "logoUrl": "http://upload.dev.rockcent.com/images/20160513/20160513161517vQKacK6S.png",
     *              "type":"DISCOUNT",
     *              "faceValue":"30",
     *              "discount":"8.5",
     *              "limitAmount":"200",
     *              "dateEnabled":"2016-06-01 14:13:43",
     *              "dateDisabled":"2016-06-01 14:13:43",
     *              "useScope": "PART_PRODUCT"
     *              },
     *              .......
     *          }]
     *      }
     *  }
     */
    @RequestMapping(value = Routes.CUSTOMER_COUPON_PAGE, method = RequestMethod.GET)
    public JsonResult customerCouponPage(HttpServletRequest request, String couponStatus, Integer pageNo, Integer pageSize) {
        CustomerDto customerDto = customerHelper.getSession(request);
        RestDoing doing = jr -> {
            if (StringUtils.isBlank(couponStatus)) {
                jr.remind("卡券状态 不能为空",log);
                return;
            }
            PageResult<MerchantCouponDto> pageResult = customerCouponWalletRepository.findCustomerCouponPage(customerDto.getId(), couponStatus, this.getPage(pageNo, pageSize));
            pageResult.setUrl(Routes.CUSTOMER_COUPON_PAGE);
            jr.data = pageResult;
        };
        return doing.go(request, log);
    }

    /**
     * @api {get} /api/v2/customer/coupon/statistics 我的卡卷__统计
     * @apiGroup CUSTOMER_COUPON
     *
     * @apiHeader {String} domain <code>必须参数</code>对应平台C端域名
     * @apiHeader {String} userToken <code>必须参数</code>用户Token
     *
     * @apiSuccess {Long} customerId 用户ID
     * @apiSuccess {String} toUserCount 待使用
     * @apiSuccess {BigDecimal} usedCount 已使用
     * @apiSuccess {BigDecimal} expiredCount 已过期
     * @apiSuccessExample {json} Success-Response:
     * {
     *  "code": "1",
     *  "desc": "成功",
     *  "data": {
     *              "customerId": 93,
     *              "toUserCount": 22,
     *              "usedCount": 0,
     *              "expiredCount": 1
     *          }
     *  }
     */
    @RequestMapping(value = Routes.CUSTOMER_COUPON_STATISTICS, method = RequestMethod.GET)
    public JsonResult customerCouponStatistics(HttpServletRequest request) {
        CustomerDto customerDto = customerHelper.getSession(request);
        RestDoing doing = jr -> {
            MerchantCouponStatisticsDto statisticsDto = new MerchantCouponStatisticsDto();
            statisticsDto.setCustomerId(customerDto.getId());
            Long toUse = customerCouponWalletRepository.countByCustomerIdAndStatusAndIsDelete(customerDto.getId(), CustomerCouponWalletStatus.TO_USE, Whether.NO);
            Long used = customerCouponWalletRepository.countByCustomerIdAndStatusAndIsDelete(customerDto.getId(), CustomerCouponWalletStatus.USED, Whether.NO);
            Long expired = customerCouponWalletRepository.countByCustomerIdAndDateDisabledBeforeNow(customerDto.getId());
            statisticsDto.setToUserCount(toUse);
            statisticsDto.setUsedCount(used);
            statisticsDto.setExpiredCount(expired);
            jr.setData(statisticsDto);
        };
        return doing.go(request, log);
    }

    /**
     * @api {put} /api/v2/customer/coupon/wallet/for_order 我的卡卷可用于订单里的券
     * @apiGroup CUSTOMER_COUPON
     *
     * @apiHeader {String} domain <code>必须参数</code>对应平台C端域名
     * @apiHeader {String} userToken <code>必须参数</code>用户Token
     *
     * @apiParam {Long} buyProductList_buyId <code>必须参数</code>产品id
     * @apiParam {Long} buyProductList_buyCount <code>必须参数</code>产品购买数量
     *
     * @apiSuccess {String} num 持有数量
     * @apiSuccessExample {json} Success-Response:
     *  {
     *      "code": 1,
     *      "desc": "成功",
     *      "data" :{
     *          "data": [{
     *              {
     *              "id": 5,
     *              "logoUrl": "http://upload.dev.rockcent.com/images/20160513/20160513161517vQKacK6S.png",
     *              "type":"DISCOUNT",
     *              "faceValue":"30",
     *              "discount":"8.5",
     *              "limitAmount":"200",
     *              "dateEnabled":"2016-06-01 14:13:43",
     *              "dateDisabled":"2016-06-01 14:13:43",
     *              "useScope": "PART_PRODUCT"
     *              },
     *              .......
     *          }]
     *      }
     *  }
     */
    @RequestMapping(value = Routes.CUSTOMER_COUPON_WALLET_FOR_ORDER, method = RequestMethod.PUT)
    public JsonResult customerCouponWalletForOrder(HttpServletRequest request, @RequestBody BuyOrderDto dto) {
        CustomerDto customerDto = customerHelper.getSession(request);
        RestDoing doing = jr -> {

            if (dto.getBuyProductList() == null || dto.getBuyProductList().size() == 0) {
                jr.remind("购买产品  不能为空",log);
                return;
            }
            List<MerchantCouponDto> merchantCoupons = new ArrayList<>();
            List<Long> productIdList = dto.getBuyProductList().stream().map(BuyProductDto::getBuyId).collect(Collectors.toList());
//            log.info("======================>productIdList:{}",productIdList);
            if(productIdList==null || productIdList.size()==0) {
                jr.remind("购买产品  不能为空",log);
                return;
            }
            List<Product> productList = merchantProductRepository.findByIdInAndMarketIdIsNull(productIdList);
//            log.info("======================>productList:{}",productList);
            if (productList != null && productList.size() > 0) {
                //购买产品    按产品ID分组
                Map<Long, BuyProductDto> buyProductMap = dto.getBuyProductList().stream().collect(Collectors.toMap(BuyProductDto::getBuyId, product -> product));
                //根据商家ID,产品分组
                Map<Long, List<Product>> groupByMerchantProductMap = new HashMap<>();
                productList.forEach(product -> {
                    groupByMerchantProductMap.computeIfAbsent(product.getMerchantId(), k -> new ArrayList<>()); // 如果key不存在，那么设置一个值进去使用 computeIfAbsent
                    groupByMerchantProductMap.get(product.getMerchantId()).add(product);
                });

                //获取可用卡卷
                List<Long> merchantIdList = productList.stream().map(Product::getMerchantId).collect(Collectors.toList());
//                log.info("======================>merchantIdList:{}",merchantIdList);
                List<MerchantCouponDto> merchantCouponDtoList = customerCouponWalletRepository.findOrderForMyCoupon(customerDto.getId(), merchantIdList);


                for (MerchantCouponDto merchantCouponDto : merchantCouponDtoList) {
                    if (MerchantCouponStatus.valueOf(merchantCouponDto.getStatus()) != MerchantCouponStatus.ISSUED && MerchantCouponStatus.valueOf(merchantCouponDto.getStatus()) != MerchantCouponStatus.SOLDOUT) {
                        continue;
                    }
                    List<Product> merchantProductList = groupByMerchantProductMap.get(merchantCouponDto.getMerchantId());

                    BigDecimal productPriceSum = BigDecimal.ZERO;
                    //可用全部产品
                    if (CouponUseScope.valueOf(merchantCouponDto.getUseScope()) == CouponUseScope.ALL_PRODUCT) {
                        for (Product product : merchantProductList) {
                            BuyProductDto buyProductDto = buyProductMap.get(product.getId());
                            BigDecimal productPrice = product.getSellPrice().multiply(new BigDecimal(buyProductDto.getBuyCount()));
                            productPriceSum = productPriceSum.add(productPrice);
                            if (productPriceSum.compareTo(new BigDecimal(merchantCouponDto.getLimitAmount())) > -1) {
                                merchantCoupons.add(merchantCouponDto);
                                break;
                            }

                        }
                    }

                    //部分产品可用
                    if (CouponUseScope.valueOf(merchantCouponDto.getUseScope()) == CouponUseScope.PART_PRODUCT) {
                        List<MerchantCouponProducts> merchantCouponProductsList = merchantCouponProductsRepository.findByCouponIdAndIsDelete(merchantCouponDto.getId(), Whether.NO);
                        List<Long> partProductIdList = merchantCouponProductsList.stream().map(MerchantCouponProducts::getProductId).collect(Collectors.toList());
                        for (Product product : merchantProductList) {
                            if (partProductIdList.contains(product.getId())) {
                                BuyProductDto buyProductDto = buyProductMap.get(product.getId());
                                BigDecimal productPrice = product.getSellPrice().multiply(new BigDecimal(buyProductDto.getBuyCount()));
                                productPriceSum = productPriceSum.add(productPrice);
                                if (productPriceSum.compareTo(new BigDecimal(merchantCouponDto.getLimitAmount())) > -1) {
                                    merchantCoupons.add(merchantCouponDto);
                                    break;
                                }
                            }
                        }
                    }

                    //计算最优惠优惠券
                    if (merchantCoupons.size() > 0) {
                        // 检查购买产品字段
                        for (int i = 0; i < dto.getBuyProductList().size(); i++) {
                            BuyProductDto buyProduct = dto.getBuyProductList().get(i);
                            Product product = merchantProductRepository.findOne(buyProduct.getBuyId());
                            // 以上检验通过,把所有关于产品的属性copy一次
                            if (product.getMarketId() == null) {
                                product.setMarketId(0L);
                            }
                            RBeanUtils.copyProperties(product, buyProduct);
                        }
                        BigDecimal discountAmount = BigDecimal.ZERO;
                        BigDecimal temp = BigDecimal.ZERO;
                        for (int i = 0; i < merchantCoupons.size(); i++) {
                            MerchantCouponDto merchantCoupon = merchantCoupons.get(i);
                            MerchantCoupon coupon = merchantCouponRepository.findOne(merchantCoupon.getId());
                            List<MerchantCouponProducts> merchantCouponProductsList = merchantCouponProductsRepository.findByCouponId(merchantCoupon.getId());
                            discountAmount = OrderHelper.SINGLEONE.calculatedMallOrderCouponDiscountAmount(dto.getBuyProductList(), merchantCouponProductsList, coupon);
                            merchantCoupon.setMostFavorable(Whether.NO.toString());
                            if (i == 0) {
                                temp = discountAmount;
                                merchantCoupon.setMostFavorable(Whether.YES.toString());
                            }
                            if (discountAmount.compareTo(temp) > 0) {
                                temp = discountAmount;
                                merchantCoupon.setMostFavorable(Whether.YES.toString());
                                merchantCoupons.get(0).setMostFavorable(Whether.NO.toString());
                            }
                        }
                    }
                }
            }


        jr.data = merchantCoupons;
    }

    ;
    return doing.go(request,log);
}

    /**
     * @api {get} /api/v2/coupon/info 卡卷详情
     * @apiGroup COUPON
     *
     * @apiHeader {String} domain <code>必须参数</code>对应平台C端域名
     * @apiHeader {String} userToken <code>必须参数</code>用户Token
     *
     * @apiParam {Long} id 卡券ID
     *
     * @apiSuccess {Long} id 卡券ID
     * @apiSuccess {String} logoUrl 卡卷图片
     * @apiSuccess {String=VOUCHERS("抵用券"), DISCOUNT("折扣券")} type 卡片类型
     * @apiSuccess {BigDecimal} faceValue 面值
     * @apiSuccess {BigDecimal} discount 折扣
     * @apiSuccess {BigDecimal} limitAmount 最低消费金额
     * @apiSuccess {Date} dateEnabled 有效开始时间
     * @apiSuccess {Date} dateDisabled 有效结束时间
     * @apiSuccess {String=ALL_STORE("所有门店"), ALL_PRODUCT("所有产品"), PART_STORE("指定门店"), PART_PRODUCT("指定产品")} useScope 适用范围
     * @apiSuccess {Long} leaveTotal 剩余数量
     * @apiSuccessExample {json} Success-Response:
     *  {
     *    "code": "1",
     *    "desc": "成功",
     *    "data": {
     *      "id": 221,
     *      "dateCreated": "2016-11-28 15:57:27",
     *      "lastUpdated": "2016-11-28 16:07:58",
     *      "version": 2,
     *      "type": "VOUCHERS",
     *      "name": "到店立减10元",
     *      "faceValue": 10,
     *      "limitAmount": 10,
     *      "quantity": 99,
     *      "leaveTotal": 100,
     *      "dateEnabled": "2016-11-28 15:56:48",
     *      "dateDisabled": "2017-11-28 15:56:48",
     *      "useScope": "ALL_STORE",
     *      "dateIssued": "2016-11-28 15:57:27",
     *      "drawLimit": "ALL",
     *      "limitCount": 1,
     *      "sharing": "YES",
     *      "showOnCenter": "NO",
     *      "showOnMerchant": "YES",
     *      "logoUrl": "http://uploads.rockcent.com//uat/product/face/201611/281557226543eaeb918-5652-45fd-8ceb-8e37990ff6b1/卡券10元.png",
     *      "introduction": "无",
     *      "status": "ISSUED",
     *      "merchantId": 50,
     *      "promoteUrl": "http://uploads.rockcent.com/uat/coupon/promote/201611/2816757198090a502a-f763-4950-8c58-d5726a70ca0echannelSendOutQR.jpg",
     *      "mallId": 1,
     *      "quantityFrozen": 0,
     *      "quantityUsed": 0
     *    }
     *  }
     *
     */
    @RequestMapping(value = Routes.CUSTOMER_COUPON_INFO, method = RequestMethod.GET)
    public JsonResult customerCouponInfo(HttpServletRequest request, Long id) {
        CustomerDto customerDto = customerHelper.getSession(request);
        RestDoing doing = jr -> {
            if (id == null) {
                jr.remind(MerchantCoupon.CHECK_ID_IS_NOT_NULL,log);;
                return;
            }
            MerchantCouponDto coupon = customerCouponWalletRepository.findCustomerCouponInfo(id, customerDto.getId());
            if (coupon == null) {
                jr.remind(MerchantCoupon.REMIND_RECORD_IS_NOT_EXIST,log);;
                return;
            }

            if (CouponUseScope.ALL_STORE == CouponUseScope.valueOf(coupon.getUseScope())) {
                List<MerchantStore> merchantStoreList = merchantStoreRepository.findByMerchantIdAndExchangeAndStatusAndIsDelete(coupon.getMerchantId(), Whether.YES, MerchantStoreStatus.ENABLE, Whether.NO);
                coupon.setCouponStoreCount(Long.valueOf(merchantStoreList.size()));
            } else if (CouponUseScope.PART_STORE == CouponUseScope.valueOf(coupon.getUseScope())) {
                List<CouponMerchantStore> couponMerchantStoreList = couponMerchantStoreRepository.findByCouponIdAndIsDelete(coupon.getId(), Whether.NO);
                coupon.setCouponStoreCount(Long.valueOf(couponMerchantStoreList.size()));
            }
            jr.data = coupon;
        };
        return doing.go(request, log);
    }


    @RequestMapping(value = Routes.COUPON_INFO, method = RequestMethod.GET)
    public JsonResult couponInfo(HttpServletRequest request, Long id) {
        RestDoing doing = jr -> {
            if (id == null) {
                jr.remind(MerchantCoupon.CHECK_ID_IS_NOT_NULL,log);;
                return;
            }
            MerchantCoupon coupon = couponRepository.findOne(id);
            if (coupon == null) {
                jr.remind(MerchantCoupon.REMIND_RECORD_IS_NOT_EXIST,log);;
                return;
            }
            jr.data = coupon;
        };
        return doing.go(request, log);
    }


    /**
     * @api {get} /api/v2/customer/coupon/merchant/store/List 卡卷适合兑换的所有门店列表
     * @apiGroup merchant
     *
     * @apiParam {Long} couponId 卡券ID
     * @apiParam {String} useScope 卡卷使用范围ALL_STORE(全部门店)PART_STORE(部分门店)
     * @apiParam {Long} merchantId 商家ID
     *
     * @apiSuccess {String} locationStr 区域
     * @apiSuccess {String} address 街道地址
     * @apiSuccess {String} third 地址
     * @apiSuccess {String} phone 联系电话
     * @apiSuccess {String} name 门店名
     * @apiSuccess {String} exchange 可否兑换
     * @apiSuccess {String} type 门店类型
     * @apiSuccessExample {json} Success-Response:
     * HTTP/1.1 200 OK
     *  {
     *      "code": 1,
     *      "desc": "成功",
     *      "data":{
     *          "data": [
     *              {
     *                  "locationStr" : "广东省从化市",
     *                  "address": "江埔街凤院村源龙队68号",
     *                  "phone": "15920385185,15920385186,",
     *                  "name": "xxxx门店1",
     *                  "id": 1
     *              }
     *          ]
     *      }
     *  }
     */
    @RequestMapping(value = Routes.CUSTOMER_COUPON_MERCHANT_STORE_LIST, method = RequestMethod.GET)
    public JsonResult customerCouponMerchantStore(HttpServletRequest request, Long couponId, String useScope, Long merchantId) {
        RestDoing doing = jr -> {
            if (merchantId == null) {
                jr.remind("商家ID 不能为空",log);
                return;
            }
            if (couponId == null) {
                jr.remind("卡卷couponId 不能为空",log);
                return;
            }
            if (StringUtils.isBlank(useScope)) {
                jr.remind("卡卷使用范围 不能为空",log);
                return;
            }
            List<MerchantStore> merchantStoreList = new ArrayList<>();
            if (CouponUseScope.ALL_STORE == CouponUseScope.valueOf(useScope)) {
                merchantStoreList = merchantStoreRepository.findByMerchantIdAndExchangeAndStatusAndIsDelete(merchantId, Whether.YES, MerchantStoreStatus.ENABLE, Whether.NO);
            } else if (CouponUseScope.PART_STORE == CouponUseScope.valueOf(useScope)) {
                merchantStoreList = merchantStoreRepository.findCustomerCouponMerchantStore(couponId);
            }
            jr.data = merchantStoreList;
        };
        return doing.go(request, log);
    }

    /**
     * @api {put} /api/v2/customer/coupon/scan/verify 扫码核销
     * @apiGroup CUSTOMER_COUPON
     *
     * @apiHeader {String} domain <code>必须参数</code>对应平台C端域名
     * @apiHeader {String} userToken <code>必须参数</code>用户Token
     *
     * @apiParam {String} verifyKey <code>必传参数</code> 核销兑换码
     * @apiParam {Long} verifierId <code>必传参数</code> 核销员ID
     * @apiParam {Long} merchantId <code>必传参数</code> 商家ID
     *
     * @apiSuccess {String} code 1:代表成功, 3:代表温馨提示, 5:代表核销员工不存在
     *
     * @apiSuccessExample {json} Success-Response:
     *      {
     *      "code": 1,
     *      "desc" : "成功"
     *      }
     */
    @RequestMapping(value = Routes.CUSTOMER_COUPON_SCAN_VERIFY, method = RequestMethod.PUT)
    public JsonResult customerCouponScanVerify(HttpServletRequest request, @RequestBody QrCodeDto dto) {
        CustomerDto customerDto = customerHelper.getSession(request);
        RestDoing doing = jr -> {
            if (StringUtils.isBlank(dto.getVerifyKey())) {
                jr.remind("核销兑换码 不能为空",log);
                return;
            }
            if (dto.getVerifierId() == null) {
                jr.remind("核销员工ID 不能为空",log);
                return;
            }
            if (dto.getMerchantId() == null) {
                jr.remind("商家ID 不能为空",log);
                return;
            }
            MerchantStoreCustomer merchantStoreCustomer = merchantStoreCustomerRepository.findByVerifyPersonIdAndMerchantIdAndIsDelete(dto.getVerifierId(), dto.getMerchantId(), Whether.NO);
            if (merchantStoreCustomer == null) {
                jr.custom("5", "核销员工不存在", log);
                return;
            }

            CustomerCouponWallet customerCouponWallet = customerCouponWalletRepository.findByVerifyKeyAndStatusAndIsDelete(dto.getVerifyKey(), CustomerCouponWalletStatus.TO_USE, Whether.NO);
            if (customerCouponWallet == null) {
                jr.remind("此二维码无效",log);
                return;
            }
            MerchantCoupon merchantCoupon = merchantCouponRepository.findByIdAndStatus(customerCouponWallet.getCouponId(), MerchantCouponStatus.ISSUED);
            if (merchantCoupon == null) {
                jr.remind("此二维码卡卷不存在",log);
                return;
            }

            if (merchantCoupon.getStatus() == MerchantCouponStatus.EXPIRED) {
                jr.remind("此优惠券已经过期,不能进行兑换",log);
                return;
            }

            if (merchantCoupon.getDateDisabled().getTime() < new Date().getTime()) {
                jr.remind("此优惠券已经过期,不能进行兑换",log);
                return;
            }

            if (CouponUseScope.ALL_STORE != merchantCoupon.getUseScope() && CouponUseScope.PART_STORE != merchantCoupon.getUseScope()) {
                jr.remind("卡券" + merchantCoupon.getName() + "不适用于线下门店核销!",log);
                return;
            }

            if (CouponUseScope.PART_STORE == merchantCoupon.getUseScope()) {
                List<CouponMerchantStore> couponMerchantStoreList = couponMerchantStoreRepository.findByCouponIdAndIsDelete(merchantCoupon.getId(), Whether.NO);
                List<Long> couponIds = couponMerchantStoreList.stream().map(CouponMerchantStore::getCouponId).collect(Collectors.toList());
                if (!couponIds.contains(merchantCoupon.getId())) {
                    jr.remind("此优惠券不适合在本店消费",log);
                    return;
                }
            }

            MerchantStore merchantStore = merchantStoreRepository.findByIdAndMerchantIdAndMallIdAndIsDelete(merchantStoreCustomer.getStoreId(), merchantCoupon.getMerchantId(), merchantCoupon.getMallId(), Whether.NO);
            if (merchantStore == null) {
                jr.remind("商家不存在此间门店",log);
                return;
            }

            customerCouponWallet.setStatus(CustomerCouponWalletStatus.USED);
            customerCouponWallet.setCustomerName(customerDto.getNickName());
            customerCouponWallet.setMerchantStoreName(merchantStore.getName());
            customerCouponWallet.setUseNum(1L);
            customerCouponWallet.setVerificationWay(OrderVerificationWay.SCAN);
            customerCouponWalletRepository.save(customerCouponWallet);

        };
        return doing.go(request, log);
    }

    /**
     * @api {get} /api/v2/customer/coupon/scan/roll 卡券扫码核销轮询
     * @apiGroup CUSTOMER_COUPON
     *
     * @apiHeader {String} domain <code>必须参数</code>对应平台C端域名
     * @apiHeader {String} userToken <code>必须参数</code>用户Token
     *
     * @apiParam {Integer} couponId <code>必传参数</code>券ID
     * @apiParam {String} verifyCode <code>必传参数</code> 核销兑换码
     *
     * @apiSuccessExample {json} Success-Response:
     *      {
     *          "code": "1",
     *          "desc": "成功",
     *          "data": true
     *      }
     */
    @RequestMapping(value = Routes.CUSTOMER_COUPON_SCAN_ROLL, method = RequestMethod.GET)
    public JsonResult customerCouponScanRoll(HttpServletRequest request, CustomerCouponWallet couponWallet) {
        CustomerDto customerDto = customerHelper.getSession(request);
        RestDoing doing = jr -> {
            if (couponWallet.getCouponId() == null) {
                jr.remind(MerchantCoupon.CHECK_ID_IS_NOT_NULL,log);;
                return;
            }
            if (StringUtils.isBlank(couponWallet.getVerifyCode())) {
                jr.remind("verifyCode can`t be null",log);
                return;
            }
            CustomerCouponWallet verifyCouponWallet = customerCouponWalletRepository.findByCustomerIdAndCouponIdAndStatusAndVerificationWayAndVerifyCode(customerDto.getId(), couponWallet.getCouponId(), CustomerCouponWalletStatus.USED, OrderVerificationWay.SCAN, couponWallet.getVerifyCode());
            if (verifyCouponWallet == null) {
                jr.remind(CustomerCouponWallet.REMIND_RECORD_IS_NOT_EXIST,log);;
                return;
            }
            jr.setData(true);

        };
        return doing.go(request, log);
    }


    /**
     * @api {put} /api/v2/customer/coupon/save 领劵
     * @apiGroup CUSTOMER_COUPON
     * @apiParam {Long} id 卡卷ID;
     * @apiParam {String} source 领取来源:  COUPON_CENTER = 领券中心 , MERCHANT = 商家 ,PROMOTE = 推广
     *
     * @apiSuccessExample {json} Success-Response:
     *  {
     *      "code": 1,
     *      "desc": "成功"
     *  }
     */
    @Transactional
    @RequestMapping(value = Routes.CUSTOMER_COUPON_SAVE, method = RequestMethod.PUT)
    public JsonResult customerCouponSave(HttpServletRequest request, @RequestBody MerchantCouponDto couponDto) {
        CustomerDto customerDto = customerHelper.getSession(request);
        RestDoing doing = jr -> {
            if (couponDto.getId() == null) {
                jr.remind(MerchantCoupon.CHECK_ID_IS_NOT_NULL,log);;
                return;
            }
            if (StringUtils.isNotBlank(couponDto.getSource()) && !EnumUtils.isValidEnum(CustomerCouponWalletSource.class, couponDto.getSource())) {
                jr.remind("领取来源只允许COUPON_CENTER(领券中心), MERCHANT(商家) ,PROMOTE(推广)",log);
                return;
            }

            List<CustomerCouponWallet> customerCouponWalletList = new ArrayList<>();

            //商家、领卷中心校验
            if (CustomerCouponWalletSource.COUPON_CENTER == CustomerCouponWalletSource.valueOf(couponDto.getSource()) || CustomerCouponWalletSource.MERCHANT == CustomerCouponWalletSource.valueOf(couponDto.getSource())) {
                customerCouponWalletList = customerCouponWalletRepository.findByCustomerIdAndCouponIdAndSource(customerDto.getId(), couponDto.getId(), CustomerCouponWalletSource.COUPON_CENTER);
                if (customerCouponWalletList.size() > 0) {
                    jr.remind("此卷每人只能领取一张",log);
                    return;
                } else {
                    customerCouponWalletList = customerCouponWalletRepository.findByCustomerIdAndCouponIdAndSource(customerDto.getId(), couponDto.getId(), CustomerCouponWalletSource.MERCHANT);
                    if (customerCouponWalletList.size() > 1) {
                        jr.remind("此卷每人只能领取一张",log);
                        return;
                    }
                }
            }

            //推广来源校验
            if (CustomerCouponWalletSource.PROMOTE == CustomerCouponWalletSource.valueOf(couponDto.getSource())) {
                customerCouponWalletList = customerCouponWalletRepository.findByCustomerIdAndCouponIdAndSource(customerDto.getId(), couponDto.getId(), CustomerCouponWalletSource.valueOf(couponDto.getSource()));
                if (customerCouponWalletList.size() > 0) {
                    MerchantCoupon coupon = merchantCouponRepository.findOne(customerCouponWalletList.get(0).getCouponId());
                    if (CouponDrawLimit.ALL == coupon.getDrawLimit() && customerCouponWalletList.size() >= coupon.getLimitCount()) {
                        jr.remind("卡券领取数量超过限制:" + coupon.getName(),log);
                        return;
                    }
                    int dayCount = 0;
                    if (CouponDrawLimit.DAYS == coupon.getDrawLimit()) {
                        Date today = RDateUtils.parseDate(DateFormatUtils.format(new Date(), RDateFormatUtils.parseDatePattern) + " 00:00:00");
                        Date nextDay = DateUtils.addDays(new Date(), 1);
                        for (CustomerCouponWallet couponWallet : customerCouponWalletList) {
                            if (couponWallet.getDateCreated().after(today) && couponWallet.getDateCreated().before(nextDay)) {
                                dayCount++;
                            }
                        }
                    }
                    if (dayCount >= coupon.getLimitCount()) {
                        jr.remind("票券每日领取数量超过限制:" + coupon.getName(),log);
                        return;
                    }
                }
            }

            //卡卷校验
            MerchantCoupon merchantCoupon = merchantCouponRepository.findOne(couponDto.getId());
            if (merchantCoupon == null) {
                jr.remind(MerchantCoupon.REMIND_RECORD_IS_NOT_EXIST,log);;
                return;
            }
            if (MerchantCouponStatus.ISSUED != merchantCoupon.getStatus()) {
                jr.remind(merchantCoupon.getName() + "卡卷状态不正确,已下架或过期",log);
                return;
            }
            if (merchantCoupon.getLeaveTotal() == 0) {

                jr.remind(merchantCoupon.getName() + ":卡卷已经领完",log);
                return;
            }
            //保存我的卡卷
            CustomerCouponWallet couponWallet = new CustomerCouponWallet();
            couponWallet.setMerchantId(merchantCoupon.getMerchantId());
            couponWallet.setCouponId(merchantCoupon.getId());
            couponWallet.setCustomerId(customerDto.getId());
            couponWallet.setMallId(merchantCoupon.getMallId());
            couponWallet.setSource(CustomerCouponWalletSource.valueOf(couponDto.getSource()));
            couponWallet.setStatus(CustomerCouponWalletStatus.TO_USE);
            couponWallet.setCustomerName(customerDto.getNickName());
            customerCouponWalletRepository.save(couponWallet);
            //更新新卡卷库存
            merchantCoupon.setLeaveTotal(merchantCoupon.getLeaveTotal() - 1);
            merchantCoupon =  merchantCouponRepository.save(merchantCoupon);
            if (merchantCoupon.getLeaveTotal() == 0) {
                String content = SysMessageConstants.SYS_COUPON_SELL_OUT.getContent();
                content = MessageFormat.format(content, merchantCoupon.getName());
                SysMessageHelper.SINGLETON.pushOpMsg(SysMessageConstants.SYS_COUPON_SELL_OUT, content, null, merchantCoupon.getMerchantId());
            }

        };
        return doing.go(request, log);
    }
}
